package com.iflytek.uc.service.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.core.io.ClassPathResource;

import com.iflytek.uc.authentication.handler.AuthenticationHandler;
import com.iflytek.uc.authentication.handler.PasswordEncoder;
import com.iflytek.uc.dao.ConfigDao;
import com.iflytek.uc.service.ConfigService;

public class ConfigServiceImpl implements ConfigService {
	
	private static final Logger LOG = Logger.getLogger(ConfigServiceImpl.class);
	
	private ConfigDao configDao;
	private String applicationTitle;
	private String rootAccount;
	private AuthenticationHandler authenticationHandler;
	private PasswordEncoder passwordEncoder;
	
	public void setConfigDao(ConfigDao configDao) {
		this.configDao = configDao;
	}

	public PasswordEncoder getPasswordEncoder() {
		if (passwordEncoder == null) {
			try {
				String v = configDao.getValue("password.encoder");
				@SuppressWarnings("rawtypes")
				Class clazz = Class.forName(v);
				passwordEncoder = (PasswordEncoder)clazz.newInstance();
			}
			catch (ClassNotFoundException e) {
				LOG.fatal("Cannot create password encoder", e);
			}
			catch (IllegalAccessException e) {
				LOG.fatal("Cannot create password encoder", e);
			}
			catch (InstantiationException e) {
				LOG.fatal("Cannot create password encoder", e);
			}
		}
		
		return passwordEncoder;
	}

	public void setPasswordEncoderClassName(String passwordEncoderClassName) {
		passwordEncoder = null;
		configDao.updateValue("password.encoder", passwordEncoderClassName);
	}

	public AuthenticationHandler getAuthenticationHandler() {
		if (authenticationHandler == null) {
			try {
				String v = configDao.getValue("authentication.handler");
				@SuppressWarnings("rawtypes")
				Class clazz = Class.forName(v);
				authenticationHandler = (AuthenticationHandler)clazz.newInstance();
			}
			catch (ClassNotFoundException e) {
				LOG.fatal("Cannot create authentication handler", e);
			}
			catch (IllegalAccessException e) {
				LOG.fatal("Cannot create authentication handler", e);
			}
			catch (InstantiationException e) {
				LOG.fatal("Cannot create authentication handler", e);
			}
		}
		
		authenticationHandler.setPasswordEncoder(getPasswordEncoder());
		return authenticationHandler;
	}

	public void setAuthenticationHandlerClassName(
			String authenticationHandlerClassName) {
		authenticationHandler = null;
		configDao.updateValue("authentication.handler", authenticationHandlerClassName);
	}

	public String getApplicationTitle() {
		if (StringUtils.isEmpty(applicationTitle)) {
			applicationTitle = configDao.getValue("application.title");
		}
		
		return applicationTitle;
	}

	public void setApplicationTitle(String applicationTitle) {
		this.applicationTitle = null;
		configDao.updateValue("application.title", applicationTitle);
	}

	public String getRootAccount() {
		if (StringUtils.isEmpty(rootAccount)) {
			rootAccount = configDao.getValue("root.account");
		}
		
		return rootAccount;
	}

	public void setRootAccount(String rootAccount) {
		this.rootAccount = null;
		configDao.updateValue("root.account", rootAccount);
	}

	public String getDatabaseType() {
		return getJdbcProperty("database.type");
	}

	public void setDatabaseType(String databaseType) {
		setJdbcProperty("database.type", databaseType);
	}

	public String getDatabaseDriver() {
		return getJdbcProperty("database.driver");
	}

	public void setDatabaseDriver(String databaseDriver) {
		setJdbcProperty("database.driver", databaseDriver);
	}

	public String getDatabaseUrl() {
		return getJdbcProperty("database.url");
	}

	public void setDatabaseUrl(String databaseUrl) {
		setJdbcProperty("database.url", databaseUrl);
	}

	public String getDatabaseUsername() {
		return getJdbcProperty("database.username");
	}

	public void setDatabaseUsername(String databaseUsername) {
		setJdbcProperty("database.username", databaseUsername);
	}

	public String getDatabasePassword() {
		return getJdbcProperty("database.password");
	}

	public void setDatabasePassword(String databasePassword) {
		setJdbcProperty("database.password", databasePassword);
	}

	public String getDatabaseValidation() {
		return getJdbcProperty("database.validation.query");
	}

	public void setDatabaseValidation(String databaseValidation) {
		setJdbcProperty("database.validation.query", databaseValidation);
	}

	public String getHibernateShowSql() {
		return getJdbcProperty("hibernate.show_sql");
	}

	public void setHibernateShowSql(String hibernateShowSql) {
		setJdbcProperty("hibernate.show_sql", hibernateShowSql);
	}

	public String getHibernateDialect() {
		return getJdbcProperty("hibernate.dialect");
	}

	public void setHibernateDialect(String hibernateDialect) {
		setJdbcProperty("hibernate.dialect", hibernateDialect);
	}

	private String getJdbcProperty(String key) {
		Properties props = getJdbcProperties();
		return props.getProperty(key);
	}
	
	private Properties getJdbcProperties() {
		Properties props = new Properties();
		InputStream stream = null;
		try {
			ClassPathResource resource = new ClassPathResource("jdbc.properties");
			stream = resource.getInputStream();
			props.load(stream);
		}
		catch (IOException e) {
			//do nothind
		}
		finally {
			try {stream.close(); } catch (Exception e) {}
		}
		return props;
	}

	private void setJdbcProperty(String key, String value) {
		Properties props = new Properties();
		InputStream inputStream = null;
		//Writer writer = null;
		OutputStream outputStream = null;
		try {
			ClassPathResource resource = new ClassPathResource("jdbc.properties");
			inputStream = resource.getInputStream();
			props.load(inputStream);
			
			File file = resource.getFile();
			//writer = new FileWriter(file);
			outputStream = new FileOutputStream(file);
			
			props.setProperty(key, value);
			props.store(outputStream, "");
		}
		catch (IOException e) {
			//do nothind
		}
		finally {
			try {inputStream.close(); } catch (Exception e) {}
			//try {writer.close(); } catch (Exception e) {}
			try {outputStream.close(); } catch (Exception e) {}
		}
	}

}
